package cn.ds.foodie.service.impl;

import cn.ds.foodie.es.pojo.Items;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import cn.ds.foodie.service.ItemsEsService;
import cn.ds.foodie.utils.PagedGridResult;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author laona
 * @decription 商品信息实现类
 * @since 2022-06-25 15:56
 **/
@Slf4j
@Service
public class ItemsEsServiceImpl implements ItemsEsService {

    @Resource
    private ElasticsearchTemplate esTemplate;

    @Override
    public PagedGridResult searchItems(String keywords, String sort, Integer page, Integer pageSize) {

        // 此处可以使用默认的 <em></em> 标签进行高亮，只需要在HTML页面中添加对应的样式
        final String PRE_TAG = "<font color='red'>";
        final String POST_TAG = "</font>";
        final String ITEM_NAME_FIELD = "itemName";
        final String SELL_COUNTS_FIELD = "sellCounts";
        final String PRICE_FIELD = "price";

        SortBuilder sortBuilder = null;
        if ("c".equalsIgnoreCase(sort)) {
            // 销量降序
            sortBuilder = new FieldSortBuilder(SELL_COUNTS_FIELD).order(SortOrder.DESC);
        } else if ("p".equalsIgnoreCase(sort)) {
            // 价格升序
            sortBuilder = new FieldSortBuilder(PRICE_FIELD).order(SortOrder.ASC);
        } else {
            // 默认：商品名称升序
            String sortStr = ITEM_NAME_FIELD + ".keyword";
            sortBuilder = new FieldSortBuilder(sortStr).order(SortOrder.ASC);
        }

        Pageable pageable = PageRequest.of(page, pageSize);

        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchQuery(ITEM_NAME_FIELD, keywords))
                // 高亮标签
                .withHighlightFields(
                        new HighlightBuilder.Field(ITEM_NAME_FIELD)
                                .preTags(PRE_TAG)
                                .postTags(POST_TAG)
                )
                // 排序规则
                .withSort(sortBuilder)
                // 分页
                .withPageable(pageable)
                .build();

        AggregatedPage<Items> pageItems = esTemplate.queryForPage(searchQuery, Items.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse resp, Class<T> aClass, Pageable pageable) {

                List<Items> itemsList = new ArrayList<>();

                // 处理高亮的内容
                SearchHits hits = resp.getHits();
                for (SearchHit hit : hits) {
                    HighlightField highlightField = hit.getHighlightFields().get(ITEM_NAME_FIELD);
                    String highlightVal = highlightField.getFragments()[0].toString();

                    Items highlightTarget = new Items();
                    Map<String, Object> source = hit.getSourceAsMap();
                    highlightTarget.setItemName(highlightVal);
                    highlightTarget.setItemId(source.get("itemId").toString());
                    highlightTarget.setImgUrl(((String) source.get("imgUrl")));
                    highlightTarget.setPrice(Integer.valueOf(source.get("price").toString()));
                    highlightTarget.setSellCounts(Integer.valueOf(source.get("sellCounts").toString()));

                    itemsList.add(highlightTarget);
                }

                return new AggregatedPageImpl<>((List<T>) itemsList, pageable, resp.getHits().totalHits);
            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {

                return null;
            }
        });
        log.info("pagedStu: {}", pageItems.getContent());

        PagedGridResult result = new PagedGridResult();
        result.setPage(page + 1);
        result.setRows(pageItems.getContent());
        result.setTotal(pageItems.getTotalPages());
        result.setRecords(pageItems.getTotalElements());

        return result;
    }
}
